package com.example.springboot.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.example.springboot.controller.request.BaseRequest;
import com.example.springboot.entity.Book;
import com.example.springboot.entity.Borrow;

import com.example.springboot.entity.ReturnBook;
import com.example.springboot.entity.User;
import com.example.springboot.exception.ServiceException;
import com.example.springboot.mapper.BookMapper;
import com.example.springboot.mapper.BorrowMapper;
import com.example.springboot.mapper.UserMapper;
import com.example.springboot.mapper.count.BorrowReturnBookCount;
import com.example.springboot.service.IBorrowService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;

@Slf4j
@Service
public class BorrowService implements IBorrowService {

    @Resource
    BorrowMapper borrowMapper;

    @Resource
    UserMapper userMapper;

    @Resource
    BookMapper bookMapper;

    @Override
    public Map<String, Object> getCountByTimeRange(String timeRange) {
        Map<String, Object> map = new HashMap<>();
        Date today = new Date();
        List<DateTime> dateRange;
        switch (timeRange) {
            case "week":
                // offsetDay 计算时间的一个工具方法
                // rangeToList 返回从开始时间到结束时间的一个时间范围
                dateRange = DateUtil.rangeToList(DateUtil.offsetDay(today, -6), today, DateField.DAY_OF_WEEK);
                break;
            case "month":
                dateRange = DateUtil.rangeToList(DateUtil.offsetDay(today, -29), today, DateField.DAY_OF_MONTH);
                break;
            case "month2":
                dateRange = DateUtil.rangeToList(DateUtil.offsetDay(today, -59), today, DateField.DAY_OF_MONTH);
                break;
            case "month3":
                dateRange = DateUtil.rangeToList(DateUtil.offsetDay(today, -89), today, DateField.DAY_OF_MONTH);
                break;
            default:
                dateRange = new ArrayList<>();
        }
        //  datetimeToDateStr()把 DateTime类型的List转换成一个 String的List
        List<String> dateStrRange = datetimeToDateStr(dateRange);
        map.put("date", dateStrRange);  // x轴的日期数据生产完毕
        //  timeRange = week  month
        // getCountByTimeRange
        List<BorrowReturnBookCount> borrowCount = borrowMapper.getCountByTimeRange(timeRange, 1);   // 1 borrow  2 return
        List<BorrowReturnBookCount> returnCount = borrowMapper.getCountByTimeRange(timeRange, 2);
        map.put("borrow", countList(borrowCount, dateStrRange));
        map.put("returnbook", countList(returnCount, dateStrRange));
        return map;
    }

    private List<String> datetimeToDateStr(List<DateTime> dateTimeList) {
        List<String> list = CollUtil.newArrayList();
        if (CollUtil.isEmpty(dateTimeList)) {
            return list;
        }
        for (DateTime dateTime : dateTimeList) {
            String date = DateUtil.formatDate(dateTime);
            list.add(date);
        }
        return list;
    }

    // 对数据库未统计的时间进行处理
    private static List<Integer> countList(List<BorrowReturnBookCount> countPOList, List<String> dateRange) {
        List<Integer> list = CollUtil.newArrayList();
        if (CollUtil.isEmpty(countPOList)) {
            return list;
        }
        for (String date : dateRange) {
            Integer count = countPOList.stream().filter(countPO -> date.equals(countPO.getDate()))
                    .map(BorrowReturnBookCount::getCount).findFirst().orElse(0);
            list.add(count);
        }
        return list;
    }



    //查询所有
    @Override
    public List<Borrow> list() {
        return borrowMapper.list();
    }

    //分页
    @Override
    public PageInfo<Borrow> page(BaseRequest baseRequest) {
        PageHelper.startPage(baseRequest.getPageNum(), baseRequest.getPageSize());
        List<Borrow> borrows = borrowMapper.listByCondition(baseRequest);
        for (Borrow borrow : borrows){
            LocalDate returnDate = borrow.getReturnTime();
            LocalDate now = LocalDate.now();
            if (now.plusDays(1).isEqual(returnDate)){
                borrow.setNote("即将到期");
            }else if (now.isEqual(returnDate)){
                borrow.setNote("已经到期");
            }else if (now.isAfter(returnDate)){
                borrow.setNote("已过期");
            }else {
                borrow.setNote("正常");
            }
        }
        return new PageInfo<>(borrows);
    }

    //更新
    @Override
    public void update(Borrow borrow) {
        borrowMapper.update(borrow);
    }


    //新增
    @Override
    @Transactional
    public void save(Borrow borrow) {
        Date date = new Date();
        borrow.setCreateTime(date);
        String userNo = borrow.getUserCardID();
        User user = userMapper.getByNo(userNo);
        if (Objects.isNull(user)) {throw new ServiceException("用户不存在");}
        Book book = bookMapper.getByISBN(borrow.getBookIsbn());
        if (Objects.isNull(book)) {throw new ServiceException("图书不存在");}
        if (book.getCounts() < 1) {throw new ServiceException("图书数量不足");}
        Integer score = user.getScore();
        Integer need = book.getScore() * borrow.getDays();
        if (need > score) {throw new ServiceException("用户书币不足");}

        book.setCounts(book.getCounts() - 1);
        user.setScore(user.getScore() - need);
        userMapper.updateById(user);
        bookMapper.update(book);

        borrow.setReturnTime(LocalDate.now().plus(borrow.getDays(), ChronoUnit.DAYS));
        borrow.setStatus("借出");
        borrowMapper.save(borrow);
        borrowMapper.saves(borrow);
    }

    @Override
    public Borrow getById(Integer id) {
        return borrowMapper.getById(id);
    }

    //删除
    @Override
    public void deleteById(Integer id) {
        borrowMapper.deleteById(id);
    }
}
